home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Utilities / PalmLink / src / PL_Socket.c < prev    next >
C/C++ Source or Header  |  2000-05-06  |  16KB  |  600 lines

  1. /**
  2.  * PalmLink -- Connect 3Com Palm with Amiga
  3.  *
  4.  * Socket Client<->Palm
  5.  *
  6.  * (C) 1998-2000 Richard Körber <rkoerber@gmx.de>
  7.  *
  8.  *------------------------------------------------------------------
  9.  *
  10.  * This program is free software; you can redistribute it and/or modify
  11.  * it under the terms of the GNU General Public License as published by
  12.  * the Free Software Foundation; either version 2 of the License, or
  13.  * any later version.
  14.  *
  15.  * This program is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  * GNU General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU General Public License
  21.  * along with this program; if not, write to the Free Software
  22.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  23.  *
  24.  * You must not use this source code to gain profit of any kind!
  25.  */
  26.  
  27. #include "strings.h"
  28. #include "palmlink_glob.h"
  29.  
  30.  
  31. #define DEFAULT_TIMEOUT       (10)        /* (sec) delay until serial timeouts */
  32. #define DEFAULT_MAXRATE       (57600)     /* max baud rate the device supports */
  33. #define ENVBUFFER_LENGTH      (2048)      /* size of env var buffer */
  34.  
  35. static const STRPTR plerrtable[] =
  36. {
  37.   "not enough memory",
  38.   "a resource is allocated",
  39.   "serial device error",
  40.   "connection timeout",
  41.   "data checksum error",
  42.   "remote: not enough memory",
  43.   "unexpected packet",
  44.   "connection is not compatible",
  45.   "serial cannot generate baud rate",
  46.   "dos error",
  47.   "PalmOS V2+ is required",
  48.   "data buffer too large",
  49.   "aborted"
  50. };
  51.  
  52. static const STRPTR dlperrtable[] =
  53. {
  54.   "no error",
  55.   "DLP: general system error",
  56.   "DLP: out of memory",
  57.   "DLP: invalid parameter",
  58.   "record not found",
  59.   "record not opened",
  60.   "record already opened",
  61.   "too many records opened",
  62.   "record does already exist",
  63.   "cannot open record",
  64.   "record is deleted",
  65.   "record is busy",
  66.   "operation not supported",
  67.   "record is read only",
  68.   "not enough space for record",
  69.   "limit exceeded",
  70.   "hotsync cancelled",
  71.   "DLP: bad arguments",
  72.   "DLP: argument is missing",
  73.   "DLP: bad argument size"
  74. };
  75.  
  76.  
  77. /*------------------------------------------------------**
  78. ** Name:        GetEnvVar                        private
  79. **
  80. ** Funktion:    Get an env variable, as string
  81. **
  82. ** Parameter:   name      Var name
  83. ** Ergebnis:    Variable Content (to be freed with FreeVec)
  84. **              or NULL if not found (or no memory)
  85. //>
  86. ** Bemerkungen:
  87. **
  88. ** Revision:    26. Oktober 1999, 01:14:08
  89. */
  90. static STRPTR GetEnvVar(STRPTR name)
  91. {
  92.   STRPTR space;
  93.   LONG result;
  94.  
  95.   space = AllocVec(ENVBUFFER_LENGTH,MEMF_PUBLIC);
  96.   if(space)
  97.   {
  98.     result = GetVar(name,space,ENVBUFFER_LENGTH,0);
  99.     if(result<0) {
  100.       FreeVec(space);
  101.       return NULL;
  102.     }
  103.   }
  104.   return(space);
  105. }
  106. //<
  107. /*------------------------------------------------------**
  108. ** Name:        GetEnvVarLong                    private
  109. **
  110. ** Funktion:    Get an env variable, as LONG
  111. **
  112. ** Parameter:   name      Variable Name
  113. **              var       LONG * to put the result to
  114. ** Ergebnis:    Success (0:failed, not 0:success)
  115. //>
  116. ** Bemerkungen:
  117. **
  118. ** Revision:    26. Oktober 1999, 01:14:08
  119. */
  120. static int GetEnvVarLong(STRPTR name, LONG *var)
  121. {
  122.   STRPTR space;
  123.  
  124.   space = GetEnvVar(name);
  125.   if(space)
  126.   {
  127.     if(-1 == StrToLong(space,var)) {
  128.       return 0;
  129.     }
  130.  
  131.     return -1;
  132.   }
  133.   else                                          // Failed
  134.   {
  135.     return 0;
  136.   }
  137. }
  138. //<
  139.  
  140.  
  141.  
  142.  
  143. /*------------------------------------------------------**
  144. ** Name:        PL_OpenSocket                     public
  145. **
  146. ** Funktion:    Erzeugt einen neuen Socket
  147. **
  148. ** Parameter:   taglist   Tagliste mit Parametern
  149. ** Ergebnis:    Socket
  150. **
  151. ** Tags:        PLTAG_ErrorPtr
  152. **              PLTAG_SerialDevice
  153. **              PLTAG_SerialUnit
  154. **              PLTAG_SerialMaxRate
  155. **              PLTAG_SerialTimeout
  156. **              PLTAG_AbortMask
  157. //>
  158. ** Bemerkungen:
  159. **
  160. ** Revision:    31. Mai 1998, 13:40:02
  161. */
  162. __saveds __asm APTR PL_OpenSocket
  163. (
  164.   register __a0 struct TagItem *taglist
  165. )
  166. {
  167.   /* Very prominent baud rates, and candidates to be provided to the Palm */
  168.   static ULONG rates[] = {115200,57600,38400,28800,19200,14400,9600,4800,2400,1200,0};
  169.  
  170.   struct PL_Socket *sock;         // Socket that has been created
  171.   LONG   *error;                  // LONG * to place error codes into
  172.   STRPTR device;                  // Device Name
  173.   ULONG  unit;                    // Device Unit
  174.   ULONG  maxrate;                 // Max Rate
  175.   ULONG  *tstbaud;
  176.   STRPTR defDevice;
  177.   LONG   defUnit = 0;
  178.   LONG   defMaxrate = DEFAULT_MAXRATE;
  179.  
  180.   /* Read env variables, if available */
  181.   defDevice = GetEnvVar("PALMLINK_DEVICE");
  182.   if(!defDevice) defDevice = "serial.device";
  183.   if(!GetEnvVarLong("PALMLINK_UNIT",&defUnit)) defUnit = 0;
  184.   if(!GetEnvVarLong("PALMLINK_RATE",&defMaxrate)) defMaxrate = DEFAULT_MAXRATE;
  185.  
  186.  
  187.   error = (LONG *)GetTagData(PLTAG_ErrorPtr,NULL,taglist);
  188.  
  189.   if(error) *error = PLERR_OKAY;
  190.  
  191.   sock = (struct PL_Socket *)AllocVec(sizeof(struct PL_Socket),MEMF_PUBLIC|MEMF_CLEAR);
  192.   if(sock)
  193.   {
  194.     sock->dlpbuffer = AllocMem(65536,MEMF_PUBLIC);
  195.     if(sock->dlpbuffer)
  196.     {
  197.       sock->timeout   = GetTagData(PLTAG_SerialTimeout,DEFAULT_TIMEOUT,taglist);
  198.       maxrate         = GetTagData(PLTAG_SerialMaxRate,defMaxrate,taglist);
  199.       sock->abortmask = GetTagData(PLTAG_AbortMask,0L,taglist);
  200.       sock->baudRate  = 9600;
  201.       sock->initiator = FALSE;
  202.       sock->transactionID = 0xFF;
  203.  
  204.       device = (STRPTR)GetTagData(PLTAG_SerialDevice,(ULONG)defDevice,taglist);
  205.       unit   =         GetTagData(PLTAG_SerialUnit  ,defUnit         ,taglist);
  206.  
  207.       if(OpenPalmSerial(sock,device,unit,9600))           // This is the default baud rate
  208.       {
  209.         /* Find out the maximum baud rate */
  210.         for(tstbaud = rates; *tstbaud; tstbaud++)
  211.         {
  212.           if(*tstbaud > maxrate) continue;                // Higher than device's max rate?
  213.           if(!PL_RawSetRate(sock,*tstbaud)) continue;     // Check if the device is able to generate that rate
  214.           break;
  215.         }
  216.         if(*tstbaud)                                      // Found a rate
  217.         {
  218.           sock->maxRate = *tstbaud;
  219. #ifdef APIDEBUG
  220.           Printf("API OpenSocket: Device max rate is %ld\n",sock->maxRate);
  221. #endif
  222.           if(PL_RawSetRate(sock,9600))                    // For this time, go back to default rate to
  223.           {                                               // establish the connection
  224.             return(sock);                 /* <------- SUCCESS -------------- */
  225.           }
  226.         }
  227.         sock->lastError = PLERR_BADBAUD;
  228.         ClosePalmSerial(sock);
  229.       }
  230.       if(error) *error = sock->lastError;
  231.       FreeMem(sock->dlpbuffer,65536);
  232.     }
  233.     FreeVec(sock);
  234.   }
  235.   if(error && (*error==PLERR_OKAY)) *error = PLERR_NOMEM;
  236.  
  237.   return(NULL);                       /* <------- FAILURE -------------- */
  238. }
  239. //<
  240.  
  241. /*------------------------------------------------------**
  242. ** Name:        PL_Accept                         public
  243. **
  244. ** Funktion:    Akzeptiere eine Verbindung vom Palm
  245. **
  246. ** Parameter:   socket    Socket zum Palm
  247. **              timeout   Timeout
  248. ** Ergebnis:    success
  249. **
  250. //>
  251. ** Bemerkungen:
  252. **
  253. ** Revision:     7. Juni 1998, 22:45:35
  254. */
  255. __saveds __asm int PL_Accept
  256. (
  257.   register __a0 APTR socket,
  258.   register __d0 ULONG timeout
  259. )
  260. {
  261.   struct PL_Socket *sock = (struct PL_Socket *)socket;
  262.   struct PL_CMP cmp;
  263.   ULONG trycnt;
  264.   ULONG tstbaud;
  265.  
  266.   sock->lastError = PLERR_OKAY;             // No errors so far
  267.   trycnt = (timeout / DEFAULT_TIMEOUT)+1;   // How many retries to fill out the timeout?
  268.  
  269.   /* Wait for CMP packet */
  270. #ifdef APIDEBUG
  271.   Printf("API Accept: Waiting for CMP Packet\n");
  272. #endif
  273.   for(;;)
  274.   {
  275.     if(PL_CMPRead(socket,&cmp)) break;      // Success!
  276.     if(sock->lastError == PLERR_TIMEOUT)    // Timeout?
  277.     {
  278.       trycnt--;
  279.       if(trycnt>0) continue;                // give it another try...
  280.     }
  281.     return(FALSE);                          // Error occured
  282.   }
  283.  
  284.   sock->version = cmp.version;              // Remember the version
  285.  
  286.   sock->lastError = PLERR_OKAY;             // Clear timeouts that may have occured
  287.  
  288.   /* Check version */
  289.   if((cmp.version & 0xFF00) != 0x0100)      // V1.0 oder V2.0 ?
  290.   {
  291.     PL_CMPAbort(socket,0x80);               // Comm not compatible
  292.     sock->lastError = PLERR_NOTCOMPATIBLE;
  293.     return(FALSE);
  294.   }
  295.  
  296.   tstbaud = min(cmp.baudrate,sock->maxRate);  // The smaller baud rate is the right one
  297.  
  298. #ifdef APIDEBUG
  299.   Printf("API Accept: Sending Init (Rate %ld)\n",tstbaud);
  300. #endif
  301.   if(!PL_CMPInit(socket,tstbaud))       // arrange this baud rate with the Palm device
  302.   {
  303.     return(FALSE);                      // Failed? Then we have no chance to connect!
  304.   }                                     // (Should not happen, 9600 should always be available)
  305.  
  306.   if(!PL_RawFlush(socket))              // Flushing meadow... :-)
  307.   {
  308.     return(FALSE);
  309.   }
  310.  
  311.   Delay(30);                            // Amiga devices seem to need some time to
  312.                                         // settle to the new rate. Wait a short moment,
  313.                                         // so we can receive the next packet with the
  314.                                         // proper baud rate. The value is experimental,
  315.                                         // but showed best results so far...
  316.  
  317. #ifdef APIDEBUG
  318.   Printf("API Accept: Changing to new baud rate %ld\n",tstbaud);
  319. #endif
  320.   if(!PL_RawSetRate(socket,tstbaud))    // now we change to the new baud rate ourselves
  321.   {
  322.     return(FALSE);                      // Failed? No chance to establish a contact. :-((
  323.   }
  324.  
  325.   if(!PL_RawFlush(socket))              // Flushing again...
  326.   {
  327.     return(FALSE);
  328.   }
  329.  
  330.   sock->baudRate = tstbaud;                 // put baud rate into socket
  331.   sock->initiator = FALSE;                  // we didn't initiate this connection
  332.  
  333. #ifdef APIDEBUG
  334.   Printf("API Accept: *done*\n");
  335. #endif
  336.  
  337.   return(TRUE);
  338. }
  339. //<
  340.  
  341. /*------------------------------------------------------**
  342. ** Name:        PL_Connect                        public
  343. **
  344. ** Funktion:    Erzeuge eine Verbindung zum Palm
  345. **
  346. ** Parameter:   socket    Socket zum Palm
  347. **              timeout   Timeout
  348. ** Ergebnis:    success
  349. **
  350. //>
  351. ** Bemerkungen:
  352. **
  353. ** Revision:     8. Juni 1998, 00:10:28
  354. */
  355. __saveds __asm int PL_Connect
  356. (
  357.   register __a0 APTR socket
  358. )
  359. {
  360.   struct PL_Socket *sock = (struct PL_Socket *)socket;
  361.   struct PL_CMP cmp;
  362.  
  363.   sock->lastError = PLERR_OKAY;             // No errors so far
  364.  
  365.   /* Wake up remote */
  366.   if(!PL_CMPWakeUp(socket,sock->maxRate))   // Try a wakeup
  367.   {
  368.     return(FALSE);                          // didn't succeed, remote still sleeping :)
  369.   }
  370.  
  371.   /* Accept suggested baud rate */
  372.   if(!PL_CMPRead(socket,&cmp))              // Read answer
  373.   {
  374.     return(FALSE);                          // failed...
  375.   }
  376.   sock->version = cmp.version;              // Remember version
  377.   switch(cmp.type)
  378.   {
  379.     case 2:                                 // Init type?
  380.       if(cmp.flags&PLCMPF_CHANGEBAUD)       // Baud rate to be changed?
  381.       {
  382.         if(!PL_RawSetRate(socket,cmp.baudrate))
  383.         {
  384.           sock->lastError = PLERR_BADBAUD;  // Doh! Amiga does not support the suggested
  385.           return(FALSE);                    // baud rate. No connection possible! :-(
  386.         }
  387.         sock->baudRate = cmp.baudrate;
  388.         Delay(50);                          // Palm needs a little time to settle
  389.                                             // to the new baud rate
  390.       }
  391.       break;
  392.  
  393.     case 3:                                 // Abort ?
  394.       sock->lastError = PLERR_NOTCOMPATIBLE;
  395.       return(FALSE);
  396.       break;
  397.  
  398.     default:                                // Something else?
  399. #ifdef DEBUGOUT
  400.   Printf("DEBUG: File %s Line %ld: Bad Packet\n",__FILE__,__LINE__);
  401. #endif
  402.       sock->lastError = PLERR_BADPACKET;
  403.       return(FALSE);
  404.   }
  405.  
  406.   sock->initiator = TRUE;                   // This time we initiated the connection
  407.   return(TRUE);                             // Okay, we are done now...
  408. }
  409. //<
  410.  
  411. /*------------------------------------------------------**
  412. ** Name:        PL_LastError                      public
  413. **
  414. ** Funktion:    Liefert den letzten Fehlercode zurück
  415. **
  416. ** Parameter:   socket    Socket zum Schließen
  417. ** Ergebnis:    error     Fehlercode
  418. //>
  419. ** Bemerkungen:
  420. **
  421. ** Revision:    31. Mai 1998, 14:09:56
  422. */
  423. __saveds __asm LONG PL_LastError
  424. (
  425.   register __a0 APTR socket
  426. )
  427. {
  428.   return(((struct PL_Socket *)socket)->lastError);
  429. }
  430. //<
  431.  
  432. /*------------------------------------------------------**
  433. ** Name:        PL_GetBaudRate                    public
  434. **
  435. ** Funktion:    Liefert die Baudrate zum Palm
  436. **
  437. ** Parameter:   socket    Socket zum Schließen
  438. ** Ergebnis:    baud      Baudrate zum Palm
  439. //>
  440. ** Bemerkungen:
  441. **
  442. ** Revision:     7. Januar 2000, 00:17:17
  443. */
  444. __saveds __asm ULONG PL_GetBaudRate
  445. (
  446.   register __a0 APTR socket
  447. )
  448. {
  449.   struct PL_Socket *sock = (struct PL_Socket *)socket;
  450.   return sock->baudRate;
  451. }
  452. //<
  453.  
  454. /*------------------------------------------------------**
  455. ** Name:        PL_Read                           public
  456. **
  457. ** Funktion:    Liest Daten vom Palm
  458. **
  459. ** Parameter:   socket    Socket zum Palm
  460. **              buffer    Datenpuffer
  461. **              size      Größe des Puffers
  462. ** Ergebnis:    length    Tatsächliche Paketgröße
  463. **
  464. //>
  465. ** Bemerkungen:
  466. **
  467. ** Revision:     8. Juni 1998, 00:10:28
  468. */
  469. __saveds __asm LONG PL_Read
  470. (
  471.   register __a0 APTR socket,
  472.   register __a1 APTR buffer,
  473.   register __d0 LONG size
  474. )
  475. {
  476.   return PL_PADPRead(socket,buffer,size);
  477. }
  478. //<
  479.  
  480. /*------------------------------------------------------**
  481. ** Name:        PL_Write                          public
  482. **
  483. ** Funktion:    Schreibt Daten zum Palm
  484. **
  485. ** Parameter:   socket    Socket zum Palm
  486. **              buffer    Datenpuffer
  487. **              size      Größe des Puffers
  488. ** Ergebnis:    length    Tatsächliche Paketgröße
  489. **
  490. //>
  491. ** Bemerkungen:
  492. **
  493. ** Revision:     8. Juni 1998, 00:10:28
  494. */
  495. __saveds __asm LONG PL_Write
  496. (
  497.   register __a0 APTR socket,
  498.   register __a1 APTR buffer,
  499.   register __d0 LONG size
  500. )
  501. {
  502.   return PL_PADPWrite(socket,buffer,size,PLPADP_DATA);
  503. }
  504. //<
  505.  
  506. /*------------------------------------------------------**
  507. ** Name:        PL_Tickle                         public
  508. **
  509. ** Funktion:    Verhindert einen Timeout
  510. **
  511. ** Parameter:   socket    Socket zum Palm
  512. ** Ergebnis:    success
  513. **
  514. //>
  515. ** Bemerkungen:
  516. **
  517. ** Revision:     8. Juni 1998, 00:26:57
  518. */
  519. __saveds __asm LONG PL_Tickle
  520. (
  521.   register __a0 APTR socket
  522. )
  523. {
  524.   UWORD dummy;
  525.   return PL_PADPWrite(socket,&dummy,0,PLPADP_TICKLE);
  526. }
  527. //<
  528.  
  529. /*------------------------------------------------------**
  530. ** Name:        PL_CloseSocket                    public
  531. **
  532. ** Funktion:    Schließt einen Socket
  533. **
  534. ** Parameter:   socket    Socket zum Schließen
  535. ** Ergebnis:
  536. //>
  537. ** Bemerkungen: Wird nur aufgerufen, wenn PL_OpenSocket()
  538. **              _nicht_ fehlschlug.
  539. **
  540. ** Revision:    31. Mai 1998, 14:07:41
  541. */
  542. __saveds __asm void PL_CloseSocket
  543. (
  544.   register __a0 APTR socket
  545. )
  546. {
  547.   struct PL_Socket *sock = (struct PL_Socket *)socket;
  548.   FreeMem(sock->dlpbuffer,65536);
  549.   ClosePalmSerial(sock);                // Close connection
  550.   FreeVec(sock);                        // Free socket
  551. }
  552. //<
  553.  
  554. /*------------------------------------------------------**
  555. ** Name:        PL_Explain                        public
  556. **
  557. ** Funktion:    Erklärt eine Fehlermeldung
  558. **
  559. ** Parameter:   error     Fehlercode
  560. **              buffer    Puffer für String
  561. **              length    Länge des Puffers (inkl. 0-Term)
  562. ** Ergebnis:
  563. //>
  564. ** Bemerkungen:
  565. **
  566. ** Revision:    10. September 1998, 01:24:21
  567. */
  568. __saveds __asm void PL_Explain
  569. (
  570.   register __a0 LONG error,
  571.   register __a1 STRPTR buffer,
  572.   register __d0 ULONG length
  573. )
  574. {
  575.   LONG negerr;
  576.  
  577.   if(error < 0)
  578.   {
  579.     negerr = (-error)-1;
  580.     if(negerr < sizeof(plerrtable))
  581.     {
  582.       stccpy(buffer,plerrtable[negerr],length);
  583.       return;
  584.     }
  585.   }
  586.  
  587.   if(error < sizeof(dlperrtable))
  588.   {
  589.     stccpy(buffer,dlperrtable[error],length);
  590.     return;
  591.   }
  592.  
  593.   Fault(error,"",buffer,length);
  594. }
  595. //<
  596.  
  597.  
  598.  
  599. /********************************************************************/
  600.